package levelrewind.android.app.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import levelrewind.android.app.model.Util.Emotion;
import levelrewind.android.app.vo.Battle;
import levelrewind.android.app.vo.BattlePerson;
import levelrewind.android.app.vo.BattleScore;
import levelrewind.android.app.vo.Category;
import levelrewind.android.app.vo.Game;
import levelrewind.android.app.vo.HighScore;
import levelrewind.android.app.vo.LatestPlayer;
import levelrewind.android.app.vo.MyNameValuePair;
import levelrewind.android.app.vo.Person;
import levelrewind.android.app.vo.PersonPlace;
import levelrewind.android.app.vo.PersonScore;
import levelrewind.android.app.vo.PicturePath;
import levelrewind.android.app.vo.User;
import levelrewind.android.app.vo.UserScore;

import org.apache.http.NameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.util.Log;

/**
 * Handler data from RESTful web service
 *
 */
public class RestDataHandler {
	private Database db;
	
	/*
	 * Country code, Remember to change it for project in difference country
	 * dk = Denmark
	 * co = Columbia
	 * int = International
	 * */
	private static final String COUNTRY_CODE = "int";
	private static final String COUNTRY_PARAM = "country_code";
	private static String addCountryCode = COUNTRY_PARAM+"="+COUNTRY_CODE;
	private static String mainUrl ="http://levelrewind.com/WS/REST/";
	private Context context;
	
	/**
	 * Date format, same as in database
	 */
	private static SimpleDateFormat sdf_dt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
	private static SimpleDateFormat sdf_d = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
	
	private static RestClient restClient = new RestClient();
		
	public RestDataHandler(Context c) {
		context = c;
		db = new Database(c); 
	}
	
	public static Game[] getGames() {
		String result = restClient.queryRESTurl(mainUrl+"getGames?"+addCountryCode);
		Game[] list = null;
        try{
        	JSONArray jArray = new JSONArray(result);
        	list = new Game[jArray.length()];
            for (int i = 0; i < jArray.length(); i++) {
            	JSONObject obj = jArray.getJSONObject(i); 
            	
            	Game game = new Game();
	            game.setId(obj.getInt("id"));
	            game.setName(obj.getString("name"));
	            game.setDescription(obj.getString("description"));
	            game.setGamePlayed(obj.getLong("games_played"));
	        	game.setPublished(obj.getString("published"));
	        	game.setIsEmbedded(obj.getInt("isEmbedded"));
	        	game.setPlatform(obj.getString("platform"));
	        	game.setAppStoreLink(obj.getString("appStoreLink"));
	        	game.setGooglePlayLink(obj.getString("googlePlayLink"));
	        	game.setIconPath(obj.getString("icon_path"));
	        	
	            list[i] = game;
            }
        }
        catch (JSONException e) {
                Log.e("JSON", "There was an error parsing the JSON", e);
        }
        
        return list;
	}
	
	public static Category[] getCategories()
	{
		String result = restClient.queryRESTurl(mainUrl+"getCategories?"+addCountryCode);
		Category[] list = null;
		if (result == null) return list;
		try {
			JSONArray jArray = new JSONArray(result);
			list = new Category[jArray.length()];
			for (int i = 0; i < jArray.length(); i++) {
				JSONObject obj = jArray.getJSONObject(i);
				Category category = new Category();
				category.setId(obj.getInt("id"));
				category.setName(obj.getString("name"));
				category.setDescription(obj.getString("description"));
				
				list[i] = category; 
			}
		}
		catch (JSONException e) {
			Log.i("JSON", "There was an error parsing the JSON", e);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		
		return list;
	}
	
	public static Person[] getPersons(int category_id)
	{		
        String url = mainUrl+"getPersonByCategory"+"?catID="+category_id+"&"+addCountryCode; 
        String result = restClient.queryRESTurl(url);
        Person[] list = null;
        if (result == null) return list;
        try{
        	JSONArray jArray = new JSONArray(result);
        	list = new Person[jArray.length()];
            for (int i = 0; i < jArray.length(); i++) {
            	JSONObject obj = jArray.getJSONObject(i); 
            	
            	Person per = new Person();
 	            per.setId(obj.getInt("id"));
 	            per.setName(obj.getString("name"));
 	            per.setCategoryId(obj.getInt("category_id"));
 	            per.setDescription(obj.getString("description"));
 	            per.setScore(obj.getLong("score"));
 	            per.setNumOfFans(obj.getLong("numOfFans"));
 	            per.setIsCurrentBattle(obj.getInt("isCurrentBattle"));
 	            
 				JSONArray paths = obj.getJSONArray("picturePathList");
 	            if (paths != null && paths.length() != 0) {
 	            	Log.i("Download PicPath", "perID: "+ per.getId());
 		            Map<Emotion, PicturePath> picMap = new HashMap<Emotion, PicturePath>();
 		            
 		            for (int j=0; j<paths.length();j++){
 			           JSONObject pobj = paths.getJSONObject(j);
 				        
 				        PicturePath pp = new PicturePath();
 				        pp.setEmotionId(pobj.getInt("emotion_id"));
 				        pp.setEmotionName(pobj.getString("emotion_name"));
 				        pp.setPath(pobj.getString("path"));

 				        Emotion emotion = Util.getEmotionByName(pp.getEmotionName());
 				        picMap.put(emotion, pp);		
 		            }
 		            
 		            per.setPicPath(picMap);	            
 	            }
 	            
 	            list[i] = per;
            }
        }
        catch (JSONException e) {
                Log.e("JSON", "There was an error parsing the JSON", e);
        }
        
        return list;
	}
	
	public static PicturePath[] getPersonPicturesPath(int person_id)
	{
		String url = mainUrl+"getPersonPicturesPath"+"?perID="+person_id+"&"+addCountryCode; 
		String result = restClient.queryRESTurl(url);
        PicturePath[] list = null;
        if (result == null) return list;
        try
        {
        	JSONArray jArray = new JSONArray(result);
        	list = new PicturePath[jArray.length()];
	        for (int i=0; i<jArray.length();i++){
	        	JSONObject obj = jArray.getJSONObject(i); 
	        	
		        PicturePath per = new PicturePath();
//	            per.setPersonId(person_id);
	            per.setEmotionId(obj.getInt("emotion_id"));
	            per.setPath(obj.getString("path"));
	            list[i] = per;
	        } 
        }
        catch (Exception ex)
        {
        	ex.printStackTrace();
         
        }
        
        return list;
	}
	
	public static PersonScore[] getPersonScores(int person_id)
	{
		String url = mainUrl+"getPersonScores"+"?perID="+person_id+"&"+addCountryCode; 
		String result = restClient.queryRESTurl(url);		
        PersonScore[] list = null;
        if (result == null) return list;
        try
        {
        	JSONArray jArray = new JSONArray(result);
	        list = new PersonScore[jArray.length()];
	        for (int i=0; i<jArray.length();i++){
	        	JSONObject obj = jArray.getJSONObject(i); 

		        PersonScore s = new PersonScore();
	            s.setPersonId(obj.getInt("person_id"));
	            s.setWeek(obj.getString("date"));
	            s.setScore(obj.getLong("score"));
	        	
	            list[i] = s;
	        } 
        }
        catch (Exception ex)
        {
        	ex.printStackTrace();
         
        }
        
        return list;
	}
	
	public static HighScore[] getHighScoreListByPerson(int person_id)
	{
		String url = mainUrl+"getHighScoreListByPerson"+"?perID="+person_id+"&"+addCountryCode; 
		String result = restClient.queryRESTurl(url);	
        HighScore[] list = null;
        if (result == null) return list;
        try
        {
        	JSONArray jArray = new JSONArray(result);
	        list = new HighScore[jArray.length()];
	        for (int i=0; i<jArray.length();i++){
	        	JSONObject obj = jArray.getJSONObject(i); 
	        	
		        HighScore hs = new HighScore();
	           // s.setPersonId(Integer.parseInt(so.getProperty(0).toString()));
		        
		        //User
		        JSONObject user = obj.getJSONObject("user");
	            User u = new User();
	            u.setId(user.getLong("id"));
	            u.setEmail(user.getString("email"));
	            u.setName(user.getString("name"));
	            
	            hs.setUser(u);
	            hs.setScore(obj.getLong("score"));
	            
	            //Game
	            JSONObject game = obj.getJSONObject("game");
	            Game g = new Game();
	            g.setId(game.getInt("id"));
	            g.setName(game.getString("name"));
	            
	            hs.setGame(g);
	            list[i] = hs;
	        } 
        }
        catch (Exception ex)
        {
        	ex.printStackTrace();
         
        }
        
        return list;
	}
 
	public static LatestPlayer[] getLatestPlayer(int person_id)
	{
		String url = mainUrl+"getLatestPlayer"+"?perID="+person_id+"&"+addCountryCode; 
		String result = restClient.queryRESTurl(url);
        LatestPlayer[] list = null;
        if (result == null) return list;
        try
        {
        	JSONArray jArray = new JSONArray(result);
	        list = new LatestPlayer[jArray.length()];
	        for (int i=0; i<jArray.length();i++){
	        	
	        	JSONObject obj = jArray.getJSONObject(i); 
	        	
	        	LatestPlayer lp = new LatestPlayer();
	        	lp.setPersonId(person_id);
		        
		        //User
		        JSONObject user = obj.getJSONObject("user");
	            User u = new User();
	            u.setId(user.getLong("id"));
	            u.setEmail(user.getString("email"));
	            u.setName(user.getString("name"));
	            
	            lp.setUser(u);
	            lp.setScore(obj.getLong("score"));
	            
	            //Game
	            JSONObject game = obj.getJSONObject("game");
	            Game g = new Game();
	            g.setId(game.getInt("id"));
	            g.setName(game.getString("name"));
	            
	            lp.setGame(g);
	            list[i] = lp;
	        } 
        }
        catch (Exception ex)
        {
        	ex.printStackTrace();
         
        }
        
        return list;
	}
	
	public static PersonPlace updatePersonScoreAndPlace(long user_id, int category_id, int person_id, int game_id, long score) {
		StringBuilder url = new StringBuilder(mainUrl+"updatePersonScoreAndPlace");
		ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new MyNameValuePair("userID", user_id+""));
		params.add(new MyNameValuePair("catID", category_id+""));
		params.add(new MyNameValuePair("perID", person_id+""));
		params.add(new MyNameValuePair("gameID", game_id+""));
		params.add(new MyNameValuePair("score", score+""));
		params.add(new MyNameValuePair(COUNTRY_PARAM, COUNTRY_CODE));
		//params.add(new MyNameValuePair("dateplayed", sdf.format(date_played))); //Changed to get current server date
		
		String result = restClient.postRESTurl(url.toString(), params);
		
		PersonPlace place = null;
        try{
        	JSONObject obj = new JSONObject(result);
            if (obj != null) {
            	place = new PersonPlace();
            	
		        place.setPersonId(person_id);
		        place.setPlaceBefore(obj.getInt("place_before"));
		        place.setPlaceNow(obj.getInt("place_now"));
		        place.setPointToFirstPlace(obj.getLong("point_to_first_place"));
		        place.setPointToTop5(obj.getLong("point_to_top5"));
		        place.setPointTo1PlaceUp(obj.getLong("point_to_1place_up"));
		        place.setTotalScore(obj.getLong("total_score"));
		        place.setScore(score);
	        	
            }
        }
        catch (JSONException e) {
                Log.e("JSON", "There was an error parsing the JSON", e);
        }
        
        return place;
        
	}

	public static Battle[] getBattles(Context context) {
		String result = restClient.queryRESTurl(mainUrl+"getBattles?"+addCountryCode);
		Battle[] list = null;
		if (result == null) return list;
		try {
			JSONArray jArray = new JSONArray(result);
			list = new Battle[jArray.length()/2];
			BattlePerson[] persons = new BattlePerson[2];
			int j = 0;
			int idx = 0;
			for (int i = 0; i < jArray.length(); i++) {
				
				JSONObject obj = jArray.getJSONObject(i);
				
				Database db = new Database(context);
		        Person p = db.getPerson(obj.getInt("person_id"));
	            BattlePerson bp = new BattlePerson();
	            bp.setBattleID(obj.getInt("id"));
	            bp.setPerson(p);
	            bp.setScore(obj.getInt("score"));
	            persons[j++] = bp;
	            
				// For each Battle has 2 persons 
				if (i % 2 != 0) {
					Battle battle = new Battle();
					battle.setId(obj.getInt("id"));
					battle.setName(obj.getString("name"));
					battle.setSlogan(obj.getString("slogan"));
					battle.setStartDate(sdf_dt.parse(obj.getString("start_date")));
					Date endDate = sdf_dt.parse(obj.getString("end_date"));
					battle.setEndDate(endDate);
					
		        	battle.setPersons(persons);
		            list[idx++] = battle; 
		            
		            // initial value
		            j = 0;
		            persons = new BattlePerson[2];
				}
			}
		}
		catch (JSONException e) {
			Log.i("JSON", "There was an error parsing the JSON", e);
		}
		catch (ParseException e) {
			Log.i("Parse", "There was an error parsing a date", e);
			e.printStackTrace();
		}
		
        return list;
	}
	
	public static Battle[] getBattlesHistory(Context context) {
		String result = restClient.queryRESTurl(mainUrl+"getBattlesHistory?"+addCountryCode);
		Battle[] list = null;
		if (result == null) return list;
		try {
			JSONArray jArray = new JSONArray(result);
			list = new Battle[jArray.length()/2];
			BattlePerson[] persons = new BattlePerson[2];
			int j = 0;
			int idx = 0;
			for (int i = 0; i < jArray.length(); i++) {
				
				JSONObject obj = jArray.getJSONObject(i);
				
				Database db = new Database(context);
		        Person p = db.getPerson(obj.getInt("person_id"));
	            BattlePerson bp = new BattlePerson();
	            bp.setBattleID(obj.getInt("id"));
	            bp.setPerson(p);
	            bp.setScore(obj.getInt("score"));
	            persons[j++] = bp;
	            
				// For each Battle has 2 persons 
				if (i % 2 != 0) {
					Battle battle = new Battle();
					battle.setId(obj.getInt("id"));
					battle.setName(obj.getString("name"));
					battle.setSlogan(obj.getString("slogan"));
					battle.setStartDate(sdf_dt.parse(obj.getString("start_date")));
					
					Date endDate = sdf_dt.parse(obj.getString("end_date"));
					battle.setEndDate(endDate);
		        	
		        	battle.setPersons(persons);
		            list[idx++] = battle; 
		            
		            // initial value
		            j = 0;
		            persons = new BattlePerson[2];
				}
			}
		}
		catch (JSONException e) {
			Log.i("JSON", "There was an error parsing the JSON", e);
		}
		catch (ParseException e) {
			Log.i("Parse", "There was an error parsing a date", e);
			e.printStackTrace();
		}
		
        return list;
	}
	
	public static BattleScore[] getBattleScores(int battle_id)
	{
		String result = restClient.queryRESTurl(mainUrl+"getBattleScores?battleID=" + battle_id+"&"+addCountryCode);
		BattleScore[] list = null;
		if (result == null) return list;
		try {
			JSONArray jArray = new JSONArray(result);
			list = new BattleScore[jArray.length()];
			for (int i = 0; i < jArray.length(); i++) {
				JSONObject obj = jArray.getJSONObject(i);
				BattleScore bs = new BattleScore();
				bs.setBattleId(obj.getInt("battle_id"));
				bs.setPersonId(obj.getInt("person_id"));
				
				JSONArray arr = obj.getJSONArray("scores");
				for (int j=0; j<arr.length();j++){ 
					JSONObject obj2 = arr.getJSONObject(j); 
					bs.addDate(sdf_d.parse(obj2.getString("date")));
					bs.addScore(obj2.getLong("score"));
				}
				list[i]= bs; 
			}
		}
		catch (JSONException e) {
			Log.i("JSON", "There was an error parsing the JSON", e);
		} catch (ParseException e) {
			Log.i("Parse", "There was an error parsing a date", e);
			e.printStackTrace();
		}
		
        return list;
	}
	
	public static boolean updateBattleScore(int battle_id, int person_id, long score) {
		StringBuilder url = new StringBuilder(mainUrl+"updateBattleScore");
		ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new MyNameValuePair("battleID", battle_id+""));
		params.add(new MyNameValuePair("personID", person_id+""));
		params.add(new MyNameValuePair("score", score+""));
		params.add(new MyNameValuePair(COUNTRY_PARAM, COUNTRY_CODE));
		
		String result = restClient.postRESTurl(url.toString(), params);
		Boolean bool = false;
		try{
        	JSONObject obj = new JSONObject(result);
            if (obj != null) {
            	bool = obj.getBoolean("result");
            	if (bool) {
            		Log.i(RestDataHandler.class.getSimpleName(), "Update battle score successful.");
            	}
            	else {
            		throw new Exception("There was an error on updating battle's score.");
            	}
            }
        }
        catch (JSONException e) {
             Log.e("JSON", "There was an error parsing the JSON", e);
        } catch (Exception e) {
        	 Log.e("UpdateBattleScore", e.getMessage());
		}
        
        return bool;
	}
	
	public static boolean CreateUser(User user) {		
		StringBuilder url = new StringBuilder(mainUrl+"createUser");
		ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
		params.add(new MyNameValuePair("id", user.getId()+""));
		params.add(new MyNameValuePair("email", user.getEmail()));
		params.add(new MyNameValuePair("name", user.getName()));
		params.add(new MyNameValuePair(COUNTRY_PARAM, COUNTRY_CODE));
		
		String result = restClient.postRESTurl(url.toString(), params);
		Boolean bool = false;
		try{
        	JSONObject obj = new JSONObject(result);
            if (obj != null) {
            	bool = obj.getBoolean("result");
            	
            	if (bool) {
            		Log.i(RestDataHandler.class.getSimpleName(), "Create new user successful");
            	}
            	else {
            		Log.i(RestDataHandler.class.getSimpleName(),"User are exist.");
            	}
            }
        }
        catch (JSONException e) {
            Log.e("JSON", "There was an error parsing the JSON", e);
        } 
        
        return bool;
	}
		
	public static UserScore[] getUserScoreByPerson(int person_id) {
		String url = mainUrl+"getUserScoreByPerson"+"?perID="+person_id+"&"+addCountryCode; 
		String result = restClient.queryRESTurl(url);
        UserScore[] list = null;
        if (result == null) return list;
        try
        {
        	JSONArray jArray = new JSONArray(result);

        	list = new UserScore[jArray.length()];
	        for (int i=0; i<jArray.length();i++){
	        	JSONObject obj = jArray.getJSONObject(i);

		        UserScore us = new UserScore();
		        us.setPersonID(obj.getInt("person_id"));
		        us.setUserID(obj.getLong("user_id"));
		        us.setScore(obj.getLong("score"));
	            list[i] = us;
	        } 
        }
        catch (Exception ex)
        {
        	ex.printStackTrace();
         
        }
        
        return list;
	}
	
	/*
	 * Download data from server to device
	 * Table : Category and Person
	 * */
	public boolean downloadData() {
		try {
			
			Category[] cats = getCategories();
			if (cats != null) db.insertCategory(cats);
			
			int all_id = -1; //id < 0 for all persons
			Person[] p = getPersons(all_id);
			if (p != null) db.insertPerson(getPersons(all_id)); 
			
			Game[] games = getGames();
			PictureHandler ph = new PictureHandler(context);
			ph.downloadGamesIconsToDevice(games);
			db.insertGame(games);

		}catch(Exception ex) {
			ex.printStackTrace();
			return false;
		}
		
		return true;
	}
	
	public Category[] getCategoriesFromDevice(){
		return db.getCategories();
	}
	
	public Person[] getPersonsFromDevice(int category_id){
		return db.getPersons(category_id);
	}
	
	public Game[] getGamesFromDevice(){
		return db.getGames();
	}
	
	public void updatePersonScoreOnDevice(int person_id, long score) {
		db.updatePersonScore(person_id, score);
	}
	
//	public long getPersonScoreFromDevice(int person_id) {
//		return db.getPersonScore(person_id);
//	}
}
